"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.crypto = void 0;
var _cryptoJs = _interopRequireDefault(require("crypto-js/crypto-js"));
var _encryptlong = require("encryptlong");
var _smCrypto = require("sm-crypto");
var _base = require("./base64");
/*
 * @Descripttion:
 * @Author: gll
 * @Date: 2023-05-19 10:30:21
 * @LastEditors: gll
 * @LastEditTime: 2023-06-13 17:57:44
 */

/** 对称加密, AES | SM4 */

/** 非对称加密, RSA | SM2 */

class AbstractEncrypt {
  /** 将对象等形式的数据转换成字符串,是否开启base64转换解决中文乱码 */
  pre(source, base64Format) {
    const data = source ? typeof source === 'object' ? JSON.stringify(source) : source.toString() : source;
    return base64Format ? (0, _base.encodeBase64)(data) : data;
  }
}

/** AES加解密 */
class AES extends AbstractEncrypt {
  key;
  iv;
  constructor(key, iv) {
    super();
    this.key = _cryptoJs.default.enc.Utf8.parse(key);
    this.iv = _cryptoJs.default.enc.Utf8.parse(iv);
  }

  /**
   * @param key 秘钥
   */
  setKey(key) {
    this.key = _cryptoJs.default.enc.Utf8.parse(key);
  }

  /**
   * @param key 偏移量
   */
  setIv(iv) {
    this.iv = _cryptoJs.default.enc.Utf8.parse(iv);
  }

  /**
   * AES加密
   * @param source
   * @returns
   */
  encrypt(source, options) {
    const word = this.pre(source);
    const {
      mode = 'ECB',
      padding = 'Pkcs7'
    } = options ?? {};
    if (!this.key) throw new Error('AES key 未设置');
    if (mode !== 'ECB' && !this.iv) throw new Error('AES iv 未设置');
    const srcs = _cryptoJs.default.enc.Utf8.parse(word);
    const ciphertext = _cryptoJs.default.AES.encrypt(srcs, this.key, {
      iv: this.iv,
      mode: _cryptoJs.default.mode[mode],
      padding: _cryptoJs.default.pad[padding]
    });
    return ciphertext.toString();
  }

  /**
   * AES解密
   * @param source
   * @returns
   */
  decrypt(source, options) {
    const {
      mode = 'ECB',
      padding = 'Pkcs7'
    } = options ?? {};
    if (!this.key) throw new Error('AES key 未设置');
    if (mode !== 'ECB' && !this.iv) throw new Error('AES iv 未设置');
    const decrypt = _cryptoJs.default.AES.decrypt(source, this.key, {
      iv: this.iv,
      mode: _cryptoJs.default.mode[mode],
      padding: _cryptoJs.default.pad[padding]
    });
    return _cryptoJs.default.enc.Utf8.stringify(decrypt).toString();
  }
}

/** RSA加解密 */
class RSA extends AbstractEncrypt {
  publicKey;
  privateKey;
  constructor(publicKey, privateKey) {
    super();
    this.publicKey = publicKey;
    this.privateKey = privateKey;
  }

  /**
   * @param publicKey 公钥
   */
  setPublicKey(publicKey) {
    this.publicKey = publicKey;
  }

  /**
   * @param privateKey 私钥
   */
  setPrivateKey(privateKey) {
    this.privateKey = privateKey;
  }

  /**
   * RSA加密
   * @param source
   * @param base64Format 是否需要进行base64转换
   * @returns
   */
  encrypt(source, base64Format) {
    const word = this.pre(source, base64Format);
    if (!this.publicKey) throw new Error('RSA publicKey 未设置');
    const encrypt = new _encryptlong.JSEncrypt();
    encrypt.setPublicKey(this.publicKey);
    return encrypt.encryptLong(word);
  }

  /**
   * RSA解密
   * @param source
   * @param base64Format 解密完成后，是否再进行base64转换
   * @returns
   */
  decrypt(source, base64Format) {
    if (!this.privateKey) throw new Error('RSA privateKey 未设置');
    const decrypt = new _encryptlong.JSEncrypt();
    decrypt.setPrivateKey(this.privateKey);
    return base64Format ? (0, _base.decodeBase64)(decrypt.decryptLong(source)) : decrypt.decryptLong(source);
  }
}

/** SM2加解密 */
class SM2 extends AbstractEncrypt {
  publicKey;
  privateKey;
  constructor(publicKey, privateKey) {
    super();
    this.publicKey = publicKey;
    this.privateKey = privateKey;
  }

  /**
   * @param publicKey 公钥
   */
  setPublicKey(publicKey) {
    this.publicKey = publicKey;
  }

  /**
   * @param privateKey 私钥
   */
  setPrivateKey(privateKey) {
    this.privateKey = privateKey;
  }

  /**
   * SM2加密
   * @param source
   * @param cipherMode 加密模式 1 - C1C3C2，0 - C1C2C3
   * @returns
   */
  encrypt(source, cipherMode = 1) {
    const word = this.pre(source);
    if (!this.publicKey) throw new Error('SM2 publicKey 未设置');
    const encrypt = _smCrypto.sm2.doEncrypt(word, this.publicKey, cipherMode);
    /** cipherMode为1时，加密密文拼接04，后端返回的密文也会以04开头 */
    return cipherMode === 1 ? `04${encrypt}` : encrypt;
  }

  /**
   * SM2解密
   * @param source
   * @param cipherMode 加密模式 1 - C1C3C2，0 - C1C2C3
   * @returns
   */
  decrypt(source, cipherMode = 1) {
    /** cipherMode为1时需要截取掉04，再进行解密 */
    const word = cipherMode === 1 ? source?.slice(2) : source;
    if (!this.privateKey) throw new Error('SM2 privateKey 未设置');
    const decrypt = _smCrypto.sm2.doDecrypt(word, this.privateKey, cipherMode);
    return decrypt;
  }
}

/** SM4加解密 */
class SM4 extends AbstractEncrypt {
  key;
  iv;
  constructor(key, iv) {
    super();
    this.key = key;
    this.iv = iv;
  }

  /**
   * @param key 秘钥
   */
  setKey(key) {
    this.key = key;
  }

  /**
   * @param iv 偏移量
   */
  setIv(iv) {
    this.iv = iv;
  }

  /**
   * SM4加密
   * @param source
   * @param options
   * @returns
   */
  encrypt(source, options) {
    const word = this.pre(source);
    const {
      mode = 'ecb',
      padding = 'pkcs#7'
    } = options ?? {};
    if (!this.key) throw new Error('SM4 key 未设置');
    if (mode === 'cbc' && !this.iv) throw new Error('SM4 iv 未设置');
    const encrypt = _smCrypto.sm4.encrypt(word, this.key, {
      iv: this.iv,
      mode,
      padding
    });
    return encrypt;
  }

  /**
   * SM4解密
   * @param source
   * @param options
   * @returns
   */
  decrypt(source, options) {
    const {
      mode = 'ecb',
      padding = 'pkcs#7'
    } = options ?? {};
    if (!this.key) throw new Error('SM4 key 未设置');
    if (mode === 'cbc' && !this.iv) throw new Error('SM4 iv 未设置');
    const decrypt = _smCrypto.sm4.decrypt(source, this.key, {
      iv: this.iv,
      mode,
      padding
    });
    return decrypt;
  }
}
/** 加解密 */
const crypto = options => {
  const {
    type = 'AES'
  } = options ?? {};
  let crypto;
  switch (type) {
    case 'AES':
      crypto = new AES();
      break;
    case 'RSA':
      crypto = new RSA();
      break;
    case 'SM2':
      crypto = new SM2();
      break;
    case 'SM4':
      crypto = new SM4();
      break;
  }
  return crypto;
};
exports.crypto = crypto;